package baduga.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;




import java.util.Set;

import baduga.core.Core_JsonDataSchema;


/**
 * @author Janek
 *
 */
public class Table extends Table_GameData { 
	
	/**
	 * Ustawienia stołu:
	 * 
	 * <pre>
	 * 0  - min. ilość graczy
	 * 1  - aktualna ilość graczy
	 * 2  - max. ilość graczy
	 * 3  - aktualna ilość obserwatorów
	 * 4  - max. ilość obserwatorów
	 * 5  - min ilość żetonów na wejście
	 * 6  - wart. małej w ciemno
	 * 7  - wart. dużej w ciemno
	 * 8 - czas ruchu gracza
	 * </pre>
	 */
	private int settingsTable[] = new int[9];
	
	/**
	 * Zwraca informacje o stole:
	 * 
	 * <pre>
	 * 0 - wolny
	 * 1 - zapełniony
	 * 2 - gra w toku
	 * 3 - zablokowany
	 * </pre>
	 * 
	 */
	private int status = 0;
	
	/**
	 * Parametry tekstowe stołu:
	 * 
	 * <pre>
	 * 0 - nazwa
	 * 1 - opis
	 * 2 - hasło
	 * </pre>
	 * 
	 */
	private String textData[] = new String[3];
	

	
	/** Identyfikator Twórcy/Administratora stołu */
	private String adminID;
	
	
	/** Identyfikator stołu */
	private String tableID;
	
	
	
	
	/** Game Thread */
	private Table_GameThread gameTh;
	
	
	
	
	/** Zawiera Talie graczy 
	 * 
	 *  nData - Dane numeryczne obowiązuje numeracja:
	 *  
	 *  <pre>
	 *   0  - min. ilość graczy
	 *   X  - aktualna ilość graczy
	 *   2  - max. ilość graczy
	 *   X  - aktualna ilość obserwatorów
	 *   4  - max. ilość obserwatorów
	 *   5  - min ilość żetonów na wejście
	 *   6  - wart. małej w ciemno
	 *   7  - wart. dużej w ciemno
	 *   8 - czas ruchu gracza
	 *   X - nr Rundy
	 *   </pre>

	 *  
	 *  tData - Dane tekstowe (Obowiązuje numeracja wg. textData)
	 *  
	 * 
	 * */
	public Table(Integer[] nData, String[] tData, Player objP)
	{

		
		/*  Parametry przepisania */
		int[] keys = {0, 2, 4, 5, 6, 7, 8};
		
		/*  Przepisanie tablicy intów */
		for(int i = 0; i < keys.length; i++)
			settingsTable[ keys[i] ] = nData[i];
		
		

		//Generuje wolne miejsca (Wymaga Settings)
		generateFreePlaces();

		
		
		
		
	    //Ustawienie ilości graczy i obserwatorów
	    settingsTable[1] = 1;
	    settingsTable[3] = 0;
	    

	    
	    /** Ustalenie admina/Twórcy */
	    this.adminID = objP.getNickName();
	    
	    /** Wrzucenie na stos */
	    this.tabPlayers.put(
			objP.getPlayerId(), 
			new Object[] {
				0, //Status
				0, //Stawka
				false, //Gotowość do gry
				0, //Czy jest na smBlind / bgBlind
				0 //Pozycja przy stole
				
			}
		);
	    
	    objP.setStatusPlayer(2);
	    
				
		
		textData = tData.clone();

		
		gameTh = new Table_GameThread(this);
		
		
	}
	
	
	
	/**
	 * Generuje listę wolnych miejsc
	 */
	private final void generateFreePlaces()
	{
		
		for(int i = 1; i < settingsTable[2]; i++)
		{
			freePlaceList.add(i);
		}
	}


	
	@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
	/**
	 * Sprawdza czy stół nie jest pełny w wariance dla obserwatorów lub
	 * 
	 * @param type określa czy sprawdzamy graczy czy obserwatorów. 0 - obserwatorzy, 1 - player
	 * @return
	 */
	private Object[] isNotFull(final int type)
	{
		//Definicja
		Object[] result;
		
		//init
		result = new Object[] {
			true, 0
		};
		
		
		if(type == 1 && status > 1 &&  settingsTable[1] + 1 > settingsTable[2])
		{
			result[0] = false;
			result[1] = 0x03EF;
			
				
		}
		else if(type == 0 && settingsTable[3] + 1 > settingsTable[4])
		{
			result[0] = false;
			result[1] = 0x03EE;
		}
		
		
		return result;
		
	}
	
	
	@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
	/**
	 * Funkcja zajmująca się operacją siadania do stołu jako gracz
	 * 
	 * @param objP
	 * @return
	 */
	public Object[] sitAsPlayer(final Player objP)
	{

		
		//Inicjalizacja
		Object[] resultOp;

		
		//Sprawdzamy, czy gracz ma prawo dołączyć.
		if(objP.getStatusPlayer() != 2 && objP.getStatusPlayer() != 0)
		{
			if(objP.getFunds() >= settingsTable[ 5 ])
			{
				
			

				
					resultOp = isNotFull(1);
					
				
					/** Czy Wolny identyfikator gracza*/
					if((boolean) resultOp[0])
					{
						//Zwiększamy ilość zajętych slotów dla graczy
						settingsTable[ 1 ] += 1;
						
						//Dokłada do sterty graczy
						tabPlayers.put(
								objP.getPlayerId(), 
								new Object[] {
									0, //Status
									0, //Stawka
									false, //Gotowość do gry
									0, //Czy jest na smBlind / bgBlind
									getFreePlaceInTable()
								}
						);
						
		
						
						//Sprawdzamy kim wcześniej był gracz (1  = gość w klasie player)
						if(objP.getStatusPlayer() == 1)
						{
						
							//Usuwa z sterty Obserwatorów
							this.tabObservers.remove(objP.getPlayerId());
							
							//Zmniejszamy ilość zajętych slotów dla obserwatora
							settingsTable[ 3 ] -= 1;
							
							//Global Event
							playerContentUpdateEvent(objP.getPlayerId(), getPlayerData( objP.getPlayerId() ));

						
						}

						
						//Ustawia status gracza
						objP.setStatusPlayer(2);
		
					}
		
			}
			else
			{
				resultOp = new Object[] {
						false, 0x03E9
					};
			}
		}
		else
		{
			resultOp = new Object[] {
					false, 0x03ED
				};
		}
		
		
		return resultOp;
	}
	
	
	
	@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
	/**
	 * Funkcja zajmująca się operacją siadania do stołu jako obserwator
	 * 
	 * @param objP
	 * @return
	 */
	public Object[] sitAsObserver(final Player objP)
	{

		
		//Inicjalizacja
		Object[] resultOp;

		
			//Sprawdzamy, czy gracz ma prawo dołączyć.
			if(objP.getStatusPlayer() != 1)
			{
				/**
				 * 
				 * Sektor atomowy, wiele graczy naraz może dołączać. :(
				 * 
				 */
				synchronized(this)
				{
				
					resultOp = isNotFull(1);
					
				
					/** Czy Wolny identyfikator gracza*/
					if((boolean) resultOp[0])
					{
						//Zwiększamy ilość zajętych slotów dla obserwatorów
						settingsTable[ 3 ] += 1;
						
						//Dokłada do sterty obserwatorów
						this.tabObservers.add(objP.getPlayerId());
	
						
						//Sprawdzamy kim wcześniej był gracz
						if(objP.getStatusPlayer() == 2)
						{

							//def.
							int absPoz;
							
							
							absPoz = (Integer) this.tabPlayers.get( objP.getPlayerId() )[4];
							
							//Pobranie jego id miejsca
							this.freePlaceList.add(absPoz );
							
							
							
							
						
							//Usuwa z sterty Graczy
							this.tabPlayers.remove( objP.getPlayerId() );
							

							
							//Zmniejszamy ilość zajętych slotów dla graczt
							settingsTable[ 1 ] -= 1;
							
							//Global Event
							playerContentUpdateEvent(objP.getPlayerId(), new Object[][] {
								new Object[] {
									absPoz
								}
							} );
						
						}
						
						//Ustawia status gracza
						objP.setStatusPlayer(1);
						
						//Ustawienie idStołu
						objP.setTableId( this.getTableId() );
		
					}
		
				}
			}
			else
			{
				resultOp = new Object[] {
						false, 0x03EC
					};
			}
		
		
		return resultOp;
	}
	

	
	
	
	
	
	
	
	@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
	/**
	 * Funkcja zajmuje się usuwanie graczy z stołu
	 * 
	 * @param objP
	 */
	public void unSitAsPlayer(Player objP)
	{

		synchronized(this)
		{
			
			//def.
			int absPoz;
			
			//Jeżeli gracz ma status gotowego oraz przy stole nie trwa gra
			if(status != 2 && isReady(objP.getPlayerId()))
			{
				gameData[2] -= 1;
				

			}
			
			absPoz = (Integer) this.tabPlayers.get( objP.getPlayerId() )[4];
			
			//Recykling wolnych miejsc
			this.freePlaceList.add( absPoz );
			
			
			//Usuwa z sterty Graczy
			this.tabPlayers.remove( objP.getPlayerId() );
			
			settingsTable[ 1 ] -= 1;
			
			
			//Global Event
			playerContentUpdateEvent(objP.getPlayerId(), new Object[][] {
				new Object[] {
					absPoz
				}
			} );
			

			
	
			//Ustawienie domyślnego statusu gracza
			objP.setStatusPlayer(0);
			objP.setTableId("");
			
			
			if(status != 2)
			{
				//Sprawdzamy status gry
				gameInitCheck();
			}
		}
	}
	
	
	
	
	@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
	/**
	 * Funkcja zajmuje się usuwaniem obserwatorów z stołu
	 * 
	 * @param objP
	 */
	public void unSitAsObserver(Player objP)
	{

		synchronized(this)
		{
			
			//Usuwa z sterty Graczy
			this.tabObservers.remove( objP.getPlayerId() );
			
			settingsTable[ 3 ] -= 1;
			
	
			//Ustawienie domyślnego statusu gracza
			objP.setStatusPlayer(0);
			objP.setTableId("");
		}
	}
	
	
	
	/**
	 * 
	 * Obsługuje migracje graczy
	 * 
	 * actions:
	 * <pre>
	 * [0] Określa typ migracji 
	 * 	0 - Imigracja / Migracja wew., 
	 * 	1 - Emigracja
	 * 
	 * [1] - Jako kto
	 * 	0 - Obserwator
	 * 	1 - Player)
	 * </pre>
	 * 
	 * 
	 * @param objP
	 * @param migrActions
	 * @return
	 */
	public Object[] playerMigrContr(Player objP, int[] migrActions)
	{
		 Object[] rData;
		 
		 

		 
		
		synchronized(this)
		{
			if(getStatus() != 3) //Jeżeli stół nie jest zablokowany
			{
				if(migrActions[0] == 0) //Dołączanie
				{
					//TODO: Czy jest w innym stole.
					if(objP.getTableId().equals("") || objP.getTableId().equals( this.tableID ) )
					{
					
						if(migrActions[1] == 0) //Obs
						{
							rData = sitAsObserver(objP);
						}
						else if (getStatus() != 2 && getStatus() != 1)	//Player
						{
							rData = sitAsPlayer(objP);
						}
						else
						{
							rData = new Object[] {
									false, 0x03EA
								};
						}
					}
					else
					{
						rData = new Object[] {
								false, 0x03DC
							};
					}
					
					
					
				}
				else //Odchodzenie
				{
					
					 //Inicjalizacja
					rData = new Object[] {
							true, null
					};
				 
					
	
					if(migrActions[1] == 0) //Obs
					{
						unSitAsObserver(objP);
					}
					else	//Player
					{
						unSitAsPlayer(objP);
					}
					
					
					//Spr. czy stół się musi zniszczyć.
					selfDestroy();
					
				}
			}
			else
			{
				
				rData = new Object[] {
						false, 0x03EB
					};
			}
		}
		
		return rData;
		
	}
	

	
	/**
	 * Sprawdza czy dany gracz może wykonać dany ruch oraz wykonuje operacje z tym związane
	 * 
	 * [moveID] - Identyfikator ruchu
	 * [data] - argumenty (np. kwota)
	 * [autoMove] - Czy ruch wywołany przez server
	 * 
	 * 
	 * 
	 * @param data
	 * @return
	 */
	public Object[] moveCheckerAndExecuter(int moveID, int[] data, Player objP, boolean autoMove)
	{
		//Def.
		Object[] result, 
				 tmpDB;
		
		Object[][] dataD2;
		
		
		//Init.
		result = new Object[] {
			false,
			null
		};
		
		dataD2 = new Object[1][];
		
		
		//Czy stół jest w trybie gry
		if(status == 2)
		{
			//Czy request podchodzi od gracza
			if(tabPlayers.containsKey(objP.getPlayerId()))
			{
				
				tmpDB = tabPlayers.get( objP.getPlayerId() );
				
				//Zmienna pomocnicza
				int tmp;
				
				//Etapy gry
				if(gameTh.getGameStage() == 2) //ruchy graczy
				{
					//Czy nie fold
					if(moveID != 5)
					{

					
						//Sprawdzenie czy aktualnie jest tura danego gracza
						if(turnData[0].equals(objP.getPlayerId()))
						{
						
						
							if(moveID == 1) //Bet
							{
								//Sprawdzamy czy pierwszy zakład jest kwotą dodatnia & czy stać gracza na niego
								if(playerMovePermission[0] == 1 && data[0] > 0 && objP.checkFunds(data[0]))
								{
									//Ustawienie 1-szego zakładu
									
									//ściągnie od gracza funduszy
									objP.setFunds(-data[0]);
									
									//Ustawienie Bid Gracza
									tmpDB[1] = data[0];
									
									//Ustawienie Bid stołu
									gameData[1] = data[0];
									
									//Aktualizacja póli stołu
									gameData[0] = data[0];
									
									//gracze z takimsamym zakładem
									gameData[2] = 1;
									
									
									
									dataD2[0] = new Object[] {
										objP.getFunds(),
										tmpDB[1], 		//BidGracza
										gameData[0],
										0x03C9,  		//Kod Wiadomości
										data[0]			//Argument
									};
									
									
									broadCastAboutPlayerMove(new int[] {1, 1}, objP.getPlayerId(), new Object[] {true, (Integer) tmpDB[4]}, dataD2);
									result[0] = true;
									
								}
								else
								{
									result[1] = 0x03A4;
								}
								
							}
							else if(moveID == 2) //Check
							{
								if(playerMovePermission[1] == 1)
								{
									
									
									dataD2[0] = new Object[] {
										0x03C8,  		
										0			
									};
									
									broadCastAboutPlayerMove(new int[] {1, 4}, objP.getPlayerId(), new Object[] {true, (Integer) tmpDB[4]}, dataD2);
		
									result[0] = true;
								}
								else
								{
									result[1] = 0x03A7;
								}
							}
							else if(moveID == 3) //Raise
							{
								
								//Sprawdzamy czy podbitka zakładu jest kwotą dodatnia & czy stać gracza na niego
								if(playerMovePermission[2] == 1 && data[0] > 0 && objP.checkFunds(data[0]))
								{
									//Aktualizacja póli gracza
									objP.setFunds(-data[0]);
									
									
									
									//Ustawienie Bid Gracza
									tmpDB[1] = data[0] + (Integer) tmpDB[1];
									
									//Ustawienie Bid stołu (różnica)
									gameData[1] += (Integer) tmpDB[1] - gameData[1];
									
									
									//Aktualizacja póli stołu
									gameData[0] += data[0];
									
									//gracze z takimsamym zakładem
									gameData[2] = 1;
									
									
									dataD2[0] = new Object[] {
										objP.getFunds(),
										tmpDB[1], 		//BidGracza
										gameData[0],
										0x03C7,  		//Kod Wiadomości
										gameData[1]			//Argument
									};
									
		
									broadCastAboutPlayerMove(new int[] {1, 1}, objP.getPlayerId(), new Object[] {true, (Integer) tmpDB[4]}, dataD2);
		
									result[0] = true;
								}
								else
								{
									result[1] = 0x03A4;
								}
								
							}
							else if(moveID == 4) //Call
							{
		
								if(playerMovePermission[3] == 1)
								{
									//Obliczenie różnicy
									tmp = gameData[1] - (Integer) tmpDB[1];
									
									//Aktualizacja póli gracza
									objP.setFunds(-tmp);
									
									
									//Ustawienie Bid Gracza
									tmpDB[1] = gameData[1];
									
									
									
									//Aktualizacja póli stołu
									gameData[0] += tmp;
									
									//gracze z takimsamym zakładem
									gameData[2] += 1;
									
									
									
									dataD2[0] = new Object[] {
										objP.getFunds(),
										tmpDB[1], 		//BidGracza
										gameData[0],
										0x03C6,  		//Kod Wiadomości
										gameData[1]			//Argument
									};
		
									broadCastAboutPlayerMove(new int[] {1, 1}, objP.getPlayerId(), new Object[] {true, (Integer) tmpDB[4]}, dataD2);
									
		
									
									endGameHandler(1, objP, tmpDB);
		
									result[0] = true;
								}
								else
								{
									result[1] = 0x03A4;
								}
								
							}
							else if(moveID == 6) //Allin
							{
								if(playerMovePermission[5] == 1)
								{
									//Pobranie resztki kasy gracza
									tmp = objP.getFunds();
									
									//Aktualizacja póli
									objP.setFunds(- (Integer) tmp);
									
									
									//Ustawienie Bid Gracza
									tmpDB[1] = tmp + (Integer) tmpDB[1];
									
									
									//Aktualizacja póli stołu
									gameData[0] += tmp;
									
		
									endGameHandler(2, objP, tmpDB);
									
									result[0] = true;
								}
								else
								{
									result[1] = 0x03A5;
								}
							}
							else
							{
								result[1] = 0x03A2;
							}
							
							
						}
						else
						{
							result[1] = 0x03A8;
						}
					}
					else 
					{
						if(moveID == 5) //FOLD
						{
							if(playerMovePermission[4] == 1)
							{
	
								endGameHandler(3, objP, tmpDB);
								
								result[0] = true;
							}
							else
							{
								result[1] = 0x03A6;
							}
						}
						else
						{
							result[1] = 0x03A8;
						}
					}
						
				}
				else if(gameTh.getGameStage() == 3) //Dobór kart
				{
					//Walidacja danych
					if(moveID == 8 && data.length > 0 && data.length < 5)
					{
						
						dataD2[0] = new Object[] {
							0x03D1,  		//Kod Wiadomości
							data.length			//Argument
						};
						
						broadCastAboutPlayerMove(new int[] {1, 4}, objP.getPlayerId(), new Object[] {true, (Integer) tmpDB[4]}, dataD2);
						
						//Wygenerowanie kart dla gracza
						
						

					}
					else if(moveID == 5) //Fold
					{
						
						endGameHandler(5, objP, tmpDB);
						
						result[0] = true;
					}
					else
					{
						result[1] = 0x03A2;
					}
				}
				else if(gameTh.getGameStage() == 1) //Dealer
				{
					//ID ruchu + spr UUID
					if(moveID == 7 && objP.getPlayerId() == dealerID[0])
					{
						
						dataD2[0] = new Object[] {
							0x03D2,  		//Kod Wiadomości
							0			//Argument
						};

						
						broadCastAboutPlayerMove(new int[] {1, 4}, objP.getPlayerId(), new Object[] {true, (Integer) tmpDB[4]}, dataD2);
						

					}
					else if(moveID == 6 && !dealerID[0].equals(objP.getPlayerId())) //AllIn (Dot. Gracza nie Dealera)
					{
						//Pobranie resztki kasy gracza
						tmp = objP.getFunds();
						
						//Aktualizacja póli
						objP.setFunds(- (Integer) tmp);
						
						
						//Ustawienie Bid Gracza
						tmpDB[1] = tmp + (Integer) tmpDB[1];
						
						
						//Aktualizacja póli stołu
						gameData[0] += tmp;


						endGameHandler(2, objP, tmpDB);
						
						result[0] = true;
					}
					else if(moveID == 5) //Fold
					{

						endGameHandler(4, objP, tmpDB);
						
						result[0] = true;
					}
					else
					{
						result[1] = 0x03A2;
					}
				}
				else if(gameTh.getGameStage() == 4) //Licytacja
				{
					
				}
				else if(gameTh.getGameStage() == 5) //Koniec gry
				{
					
				}
				else
				{
					result[1] = 0x03A1;
				}
			}
			else
			{
				result[1] = 0x03A3;
			}
			
			
		}
		else
		{
			result[1] = 0x03A0;
		}
		
		
		return result;
	}
	
	
	
	/**
	 * Funkcja wykonuje operacje związane z końcem gry.
	 * - wycofanie gracza z gry + aktualizacja danych
	 * - Detekcja czy koniec gry wystąpił
	 * - obsługa zdarzeń
	 * 
	 * <pre>
	 * [mode]
	 * 	[1] - Call EndGame
	 * 	[2] - AllIn EndGame
	 * 	[3] - Fold (Move Stage)
	 * 	[4] - Fold (Dealer Stage)
	 * 	[5] - Fold (Card Stage)
	 * </pre>
	 * 
	 * @param mode
	 * @param objP
	 * @return
	 */
	private Object[] endGameHandler(int mode, Player objP, Object[] propPlayer)
	{
		//Def,
		Object[] result;
		
		//Init.
		result = new Object[] {
			false,
			null
		};
		
		if(mode == 1) //CallEndGame
		{
			//Raczej nic do roboty nie ma.
		}
		else
		{
			//Init.
			Object[][] dataD2;
			
			//Def.
			dataD2 = new Object[1][];
			
			
			
			if(mode == 2) //AllinEndGame  (Move or SmallBling / Big Blind)
			{
				//Ustawienie statusu
				propPlayer[0] = 2;
				

				
				
				
				
				dataD2[0] = new Object[] {
					objP.getFunds(),
					propPlayer[1], 		//BidGracza
					gameData[0],
					0x03D1,  		//Kod Wiadomości
					0			//Argument
				};
				
				
				broadCastAboutPlayerMove(new int[] {1, 3}, objP.getPlayerId(), new Object[] {true, (Integer) propPlayer[4]}, dataD2);
				
				
				/*

					
					
					//BroadCast do całego Światada.
					broadCastAboutPlayerMove(new int[] {1, 4}, objP.getPlayerId(), new Object[] {true, (Integer) tmpDB[4]}, dataD2);
					*/
			}
			else
			{
				if(mode == 3) //Fold On Move stage
				{
					//Przejście do następnego gracza
				}
				else if(mode == 4) //Fold On Dealer stage
				{
					//Naciśniecie przycisku rozdaj
				}
				else if(mode == 5) //Fold On Card stage
				{
					//Nic...
				}
				
				//Ustawienie statusu
				propPlayer[0] = 1;
				
				
				
				dataD2[0] = new Object[] {
					0x03D1,  		//Kod Wiadomości
					0			//Argument
				};
				
				
				broadCastAboutPlayerMove(new int[] {1, 2}, objP.getPlayerId(), new Object[] {true, (Integer) propPlayer[4]}, dataD2);
				
			}
			
			
			/** Sprawdzenie czy gracz ma taki sam wkład jak bid stołu jeśli tak to zmniejsza jego wkład*/
			if((Integer) propPlayer[1] == gameData[1])
			{
				gameData[2] -= 1;
			}
			
			
			//Zmniejszenie ilości graczy zdolnych do gry
			gameData[4] -= 1;
			
			/** Usunięcia gracz z listy Aktywnych graczy */
			this.activePlayerList.remove((Integer) propPlayer[4]);
			
		}
		
		
		//Spr czy koniec gry
		if(!endGameTest())
		{
			
			if(endOfBid())
			{
				this.gameTh.setGameStage(3);
			}
			
		}
		else
		{
			this.gameTh.setGameStage(5);
		}
		
		

		
		
		return result;
	}
	

	
	
	/**
	 * Wyszukuje następnego gracza w Trybie gry
	 * 
	 * <pre>
	 * ndata:
	 * [0] - Tryb
	 * 0 - Dealer (Do ustawienie butona Dealera)
	 * 1 - Gracz (Do ruchów)
	 * 
	 * [1] - Start
	 * </pre>
	 * 
	 * @return [Integer pozInArray, Player pObj ]
	 */
	private Object[] findNextTarget(int[] ndata)
	{
		//Def.
		int modif = -1;
		Serwer srv;
		
		
		

		synchronized(this)
		{
		
			//Działamy na tablicy 
			if(ndata[0] == 0) //Dealer
			{
				modif = ndata[1] - 1;
				
				if(modif < 0)
				{
					modif = activePlayerList.size() - 1;
				}
				
				ndata[1] = modif;
	
			}
			else if(ndata[0] == 1) //Następny gracz (ruch)
			{
				modif = ndata[1] + 1;
				
				if(!(modif < activePlayerList.size()))
				{
					modif = 0;
				}
				
				
				ndata[1] = modif;
			}
		}

		
		srv = Controler.getcSerwer();
		
		
		
		return new Object[] {modif, srv.getPlayer( (String) activePlayerList.get(modif) [0] )};
	}
	
	
	
	/***
	 * 
	 * Funkcja ustawia Dealera, pobiera Big / SmallBlindy od graczy
	 * 
	 * 
	 */
	
	protected void setDealer()
	{
		//Def.
		Object result[], 
			   tmpPlData[];
		Player tmpP;
		boolean status;
		
		
		
		//Init.
		result = findNextTarget(new int[] {0, (Integer) dealerID[2]});
		
		/** Ustawienie Dealera */
		tmpP = (Player) result[1];
		
		dealerID[0] = tmpP.getPlayerId();
		dealerID[1] = tmpP.getNickName();
		dealerID[2] = (Integer) result[0]; //Pozycja w Tablicy
		
		
		/** SmallBlind */
		status = true;
		
		while(status)
		{
			result = findNextTarget(new int[] {0, (Integer) dealerID[2]});
			
			//Czy różny od gracza
			if((Integer) result[0] != dealerID[2])
			{
				/** Ustawienie Gracza */
				tmpP = (Player) result[1];
				
				/** Pobranie danych gracza*/
				tmpPlData = this.tabPlayers.get(tmpP.getPlayerId());
				
				if(!tmpP.checkFunds(settingsTable[6]))
				{
					
					/** Aktualizacja funduszy gracza */
					tmpP.setFunds(-settingsTable[6]);
					
					/** Ustawienie Pota Stołu */
					this.gameData[0] += settingsTable[6];
					
					/* Spr nr. rundy*/
					if(this.gameData[5] == 1)
					{
						//Ustawia Bid stołu
						this.gameData[1] = settingsTable[6];
					}
					
					
					
					/** Ustawie Bid-a Gracza + Jego status */
					tmpPlData[1] = settingsTable[6];
					
					/** Informacja, że jest na małej w ciemno*/
					tmpPlData[3] = 2;
					
				}
				else
				{
					//Zagranie AllIn Dla gracza
					moveCheckerAndExecuter(6, null, tmpP, true);
				}
				
				
				
				
			}
			else
			{
				status = false;
			}
			
			
		}
		
		
		/* Sprawdzamy warunki gry */
		
		/** BigBlind */
		if(!status)
		{
			while(status)
			{
				result = findNextTarget(new int[] {0, (Integer) dealerID[2] + 1});
				
				//Czy różny od gracza
				if((Integer) result[0] != dealerID[2])
				{
					/** Ustawienie Gracza */
					tmpP = (Player) result[1];
					
					/** Pobranie danych gracza*/
					tmpPlData = this.tabPlayers.get(tmpP.getPlayerId());
					
					if(!tmpP.checkFunds(settingsTable[7]))
					{
						
						/** Aktualizacja funduszy gracza */
						tmpP.setFunds(-settingsTable[7]);
						
						/** Ustawienie Pota Stołu */
						this.gameData[0] += settingsTable[7];
						
						/* Spr nr. rundy*/
						if(this.gameData[5] == 1)
						{
							//Ustawia Bid stołu
							this.gameData[1] = settingsTable[7];
						}
						
						
						
						/** Ustawie Bid-a Gracza + Jego status */
						tmpPlData[1] = settingsTable[7];
						
						/** Informacja, że jest na dużej w ciemno*/
						tmpPlData[3] = 1;
						
					}
					else
					{
						//Zagranie AllIn Dla gracza
						moveCheckerAndExecuter(6, null, tmpP, true);
					}
					
					
					
					
				}
				else
				{
					status = false;
				}
				
				
			}
		}
		
		
		
		/** Oczekiwanie na ruch dealera*/
		

		
	}
	
	
	
	
	
	/**
	 * Zajmuje się obsługą ruchu gracza. (Wysłanie informacji do gracza + ENV | Obsługa Timeout | Info o zakończeniu ruchu)
	 * 
	 * cfgData:
	 * [0] - IDruchu
	 *   (Informacja dla gracz o pewnych zdarzeniach: )
	 *   0 - Został wybrany na Dealera
	 *   1 - Trwa Wymiana Kart
	 *   2 - Teraz jego tura na ruch
	 *
	 * [1] - Pozycja absolutna gracza
	 * 
	 * 
	 * @param pObj
	 * @param cfgData
	 */
	public void moveControl(final Player pObj, final int cfgData[])
	{
		//Def.
		Object[][] dataD2;
		

		
		
		if(cfgData[0] == 2)
		{
			//Ustawienia ruchu gracza
			this.movePermision(pObj);

		}
		
		//Wysłanie informacji o ruchu
		broadcastAboutGameEnviromentEvent(new Object[] {1, pObj, 1}, new Object[] {true, cfgData[0]}, null);
		
		
		//Ustalenie Czasu końca i ID gracza.
		turnData[0] = pObj.getPlayerId();
		turnData[1] = this.getUnixtime() + settingsTable[8] + 1;
		
		
		
		
		/** Skonfiguratowanie wiadomości */
		dataD2 = new Object[1][];
		
		dataD2[0] = new Object[] {
			0x03D0, 	//Kod Wiadomości
			0 			//Argument
		};
		
		
		
		
		//BroadCast do całego Światada.
		broadCastAboutPlayerMove(new int[] {0, 0}, pObj.getPlayerId(), new Object[] {true, cfgData[1]}, dataD2);
		
		/** Wybudzenie wątku */
		
		try {
			this.gameTh.setSleep(true);
			Thread.sleep((Integer) turnData[1] * 1000);
			this.gameTh.setSleep(false);
		} catch (InterruptedException e) {
			this.gameTh.setSleep(false);
		}
		
		
		//Sprawdzenie Czasu
		if((Integer) turnData[1] < this.getUnixtime())
		{
			
			if(cfgData[0] == 2)
			{
				//Ustawienia ruchu gracza

			}
			else
			{
				
			}
			
			
			//Fold zagranie dla gracza
			moveCheckerAndExecuter(5, null, pObj, true);

			
		}
		
	}
	

	
	
	
	/**
	 * Bierze graczy bez statusu FOLD i All:in do Tablicy.
	 */
	public void moveLoop()
	{
		//Def.
		Serwer srv;
		int pos;
		Object[] resultOp;
		
		Player objP;
		
		
		//Init.
		srv = Controler.getcSerwer();
		
		
		//Dopóty wszyscy gracze aktywnie nie mają takiego samego zakładu || lub został odpalony trigger końca świata. 
		while(endGameTest())
		{
			pos = -1;
			
			while(pos + 1 < activePlayerList.size())
			{
				++pos;
				
				
				resultOp = srv.getPlayer((String) activePlayerList.get(0)[0]);
				
				if((boolean) resultOp[0] == true)
				{
					//Pobranie gracza
					objP = (Player) resultOp[0];
					
					
					//Ustawienie UUID
					turnData[0] = objP.getPlayerId();
					
					//Uprawnienia do ruchu | spr
					movePermision(objP);
					
					
					//Wysłanie informacji do graczy
					
					//Wysłanie informacji do gracza o jego ruchu
					
					
					//Ustawienie czasu maksymalnego
					turnData[1] = getUnixtime() + settingsTable[8];
					
				}
				
				
			}
		}
	}
	
	
	
	
	
	
	/**
	 * 
	 * Funkcja wysyła karty do wszystkich graczy
	 * 
	 * 
	 */
	public void dealCardToAllPlayers()
	{
		//Init
		Integer[] cards;
		Serwer srv;
		Object[] pData;
		
		//Def.
		srv = Controler.getcSerwer();
		
		
		for(final String objID : this.tabPlayers.keySet())
		{
			pData = this.tabPlayers.get(objID);
			
			//Czy gra jest nie foldującym
			if((Integer) pData[0] != 0)
			{
				//Pobiera 4-y Losowe karty
				cards = getNrandomCard(4);
				
				//Podpięcie do gracza kart
				assignNewCards(null, cards, objID);
				
				
				//Rozesłanie informacji do gracza
				broadcastAboutGameEnviromentEvent(
					new Object[] {
						1,  //Jeden Osobnik
						objID, //IdGracza
						0	//Etap Gry
					},
					new Object[] {
						0x03CA,
						cards.length
					},
					new Object[][] { //TODO: JEst ok zgodnie z spec.
						cards
					}
				);
			}
			
		}
		
	}
	
	
	
	
	
	
	//=====================================================================================
	
	
	
	/**
	 * 
	 * Funkcja sprawdza poprawność danych wejściowych
	 * 
	 * 
	 * nData - Dane numeryczne obowiązuje numeracja
	 * 
	 *  nData - Dane numeryczne obowiązuje numeracja
	 *   0  - min. ilość graczy
	 *   X  - aktualna ilość graczy
	 *   2  - max. ilość graczy
	 *   X  - aktualna ilość obserwatorów
	 *   4  - max. ilość obserwatorów
	 *   5  - min ilość żetonów na wejście
	 *   6  - wart. małej w ciemno
	 *   7  - wart. dużej w ciemno
	 *   8 - czas ruchu gracza
	 *  
	 *  tData - Dane tekstowe (Obowiązuje numeracja wg. textData)

	 */
	public static final Object[][] validateInput(Integer nData[], String[] tData, Player objP)
	{
		
		Object[][] rData = {
			new Object[] {
				true
			},
			null
		};
		
		//Lista
		ArrayList<Integer> tmpData = new ArrayList<Integer>();
		
		
		if(nData.length == 7 && tData.length == 3)
		{
			/**
			 * Ustawienia dla pętli
			 * Poziom: 2
			 * 
			 * 0, 1 - [Min / MAX]
			 * 2, 3 - [Kb. Min, Kb. Max]
			 * 4, 5 - [G.Cfg. Min, G.Cfg. Max.]
			 * 
			 */
			
			
			
			int settings[][] = new int[][]
			{
					new int[] {
							Game_Cfg.TAB_PLAYER_LIM[0], Game_Cfg.TAB_PLAYER_LIM[1],
							0, 0x03E8, 
							2, 0x03E7
					},
					new int[] {
							Game_Cfg.TAB_OBSERV_LIM[0], Game_Cfg.TAB_OBSERV_LIM[1],
							4, 0x03E6
					},
					new int[] {
							Game_Cfg.VALUE_BIG_BLIND[0], objP.getFunds(),
							5, 0x03E5
					},
					new int[] {
							Game_Cfg.VALUE_SMALL_BLIND[0], chooseLimit(Game_Cfg.VALUE_SMALL_BLIND[1], objP.getFunds()),
							6, 0x000, 
					},
					new int[] {
							Game_Cfg.VALUE_BIG_BLIND[0], chooseLimit(Game_Cfg.VALUE_BIG_BLIND[1], objP.getFunds()),
							7, 0x000, 
					},
					new int[] {
							Game_Cfg.PLAYER_MOVE_TIME[0], Game_Cfg.PLAYER_MOVE_TIME[1],
							8, 0x000 
					}
							
			};
			
			
			int j, 
				size;
			
			for(int i = 0; i < settings.length; i++)
			{
				j = 2;
				size = (settings[i].length - 2) / 2;
				
				for(; j < size; j += 2)
				{
					if(settings[i][j] < settings[i][0] || settings[i][j] > settings[i][1])
					{
						tmpData.add(settings[i][j + 1]);
					}
				}
				
			}
			
			
			
			
			
			//Długość hasła
			if(tData[1].length() > 0)
			{
				if(tData[1].length() < Game_Cfg.PASSWORD_LEN[0] || tData[1].length() > Game_Cfg.PASSWORD_LEN[1])
				{
					tmpData.add(0x03E1);
				}

			}
			
			
			//Opis stołu
			if(tData[2].length() > 0)
			{
				if(tData[2].length() < Game_Cfg.TAB_DESC_LIM[0] || tData[1].length() > Game_Cfg.TAB_DESC_LIM[2])
				{
					tmpData.add(0x03E2);
				}
			}
			
			
			
			if(tData[0].length() < Game_Cfg.TAB_NAME_LIM[0] || tData[0].length() > Game_Cfg.TAB_NAME_LIM[1])
			{
				tmpData.add(0x03E2);
			}

		}
		else
		{
			tmpData.add(0x03E0);
		}
		
		
		if( tmpData.size() > 0 )
		{
			rData[0][0] = false;
			
			//zwraca wszelkie błędy
			rData[1] = tmpData.toArray();
		}
		
		return rData;
	}
	
	
	
	/**
	 * 
	 * funkcja wybiera dynamicznie jaki obowiązuje limir
	 * 
	 * @param gameLim
	 * @param playLim
	 * @return
	 */
	public static int chooseLimit(int gameLim, int playLim)
	{
		
		return playLim < gameLim ? playLim : gameLim;
		
	}
	

	
	/**
	 * Samozniszczenie! 
	 */
	public void selfDestroy()
	{
		//Sprawdzenie czy nie ma graczy
		if(settingsTable[ 1 ] == 0 && settingsTable[ 3 ] == 0)
		{
			
			//Czy przy stole trwała gra.
			if(status == 2)
			{
				this.gameTh.interrupt();
				
				gameTh = null;
			}
			
			
			//Ustawienie statusu stołu
			this.status = 3;
			
			
			final Serwer srv = Controler.getcSerwer();
			
			srv.removeTable(this.tableID);

		}
		
	}
	
	
	
	
	/**
	 * 
	 * Funkcja zajmuje się aktualizacją identyfikatora stołu
	 * 
	 */
	public void updateParcipantsTabID()
	{
		
		
		final Serwer srv = Controler.getcSerwer();
		
		
		
		synchronized(this)
		{

			Object[] tmpD;
			Player tmpPl;
			
			for(final String objID : this.tabPlayers.keySet())
			{
				tmpD = srv.getPlayer(objID);
				
				if((boolean) tmpD[0] == true)
				{
					tmpPl = (Player) tmpD[1];
					
					tmpPl.setTableId(tableID);
				}
			}
			

			
			
			for(final String objID :  this.tabObservers.toArray(new String[this.tabObservers.size() ]))
			{
				tmpD = srv.getPlayer(objID);
				
				if((boolean) tmpD[0] == true)
				{
					tmpPl = (Player) tmpD[1];
					
					tmpPl.setTableId(tableID);
				}
			}
			
			tmpPl = null;
		}
		
	}
	
	
	//=====================================================================================
	
	
	/**
	 * 
	 * Funkcja rozgłaszająca wiadomości
	 * 
	 * Struktóra wiadomości:
	 * 
	 * <pre>
	 * Code, text, code, text, null
	 * </pre>
	 * 
	 * @param pID
	 * @param message
	 */
	void broadcastTextEvent(final String pID, final Object[] message)
	{

		broadcastMessageToAll(new Object[] {1 , pID}, jsonSchema(
				0x04, 
				new int[] {
					0x06
				}, 
				message,
				null));
	}
	

	
	/**
	 * 
	 * Funkcja rozgłaszająca wiadomości (Dot. zmian przy Stole)
	 * 
	 * <pre>
	 * Struktóra wiadomości:
	 * 
	 * Code, text, code, text, null
	 * </pre>
	 * 
	 * @param pID
	 * @param message
	 */
	private void playerContentUpdateEvent(final String pID, Object[][] inputData)
	{

		broadcastMessageToAll(new Object[] {0 , pID}, jsonSchema(
			0x04, 
			new int[] {
				0x07
			}, 
			null,
			inputData));
	}
	
	
	
	//=====================================================================================
	
	
	/**
	 * Przesyła informację od serwera na temat ruchu który gracz próbował wykonać
	 * 
	 * <pre>
	 * cfgData:
	 * [0] - Obiekt Gracza
	 * [1] - ID ruchu
	 * 	 1 - Bet
	 *   2 - Check
	 *   3 - Raise
	 *   4 - Call
	 *   5 - Fold
	 *   6 - AllIn
	 *   7 - Dealer
	 *   8 - CardExchange
	 *   
	 *   inputDataD1:
	 *   [0] - True/False
	 *   [1] - Komunikat błędu
	 *   
	 *   
	 *   inputDataD2:
	 *   (Dla ruchów 1, 3, 4, 6)
	 *   [0]
	 *   	[0] - Stan Konta gracza
	 *   	[1] - Całkowita Póla Stołu
	 *   	[2] - Aktualny Zakład gracza
	 *   
	 *      -- Dot. msg. o ruchu [DL - długość D2]
	 *      [DL - 2] - Kod Wiadomości
	 *      [DL - 1] - Argument wiadomości
	 *   
	 *   
	 *   (Dla ruchów 7, 5, 2)
	 *      -- Dot. msg. o ruchu [DL - długość D2]
	 *      [DL - 2] - Kod Wiadomości
	 *      [DL - 1] - Argument wiadomości
	 *   
	 *   (Dla ruchów o id 8)
	 *   [0]
	 *   	Zawiera talię kart [od 0 do 4 elementów] (Wymienione Karty)
	 * 
	 * </pre>
	 * 
	 * @param cfgData
	 * @param inputDataD1
	 * @param inputDataD2
	 */
	private void commitStatusAboutPlayerMove(final Object cfgData[], final Object[] inputDataD1, final Object[][] inputDataD2)
	{
		//Def.
		Player tmpPlayer;
		
		//Init.
		tmpPlayer = (Player) cfgData[0];
		
		
		
		tmpPlayer.getMyThread().sendData(jsonSchema(
				0x03, 
				new int[] {
					0x01,
					(Integer) cfgData[1]
							
				}, 
				inputDataD1,
				inputDataD2));
		
	}
	
	
	/**
	 * Przesyła informację na tematu ruchu gracza do innych.
	 * 
	 * <pre>
	 * cfgData:
	 * [0] - EventID
	 *    0 - start tury:
	 *    1 - Koniec tury
	 * [1] - Move Type
	 *    0 - Aktwyny gracz (Jego Ruch)
	 *    1 - Aktualizacja danych graczy (dla ruchów raise, call, bet)
	 *    2 - Fold by Own
	 *    3 - AllIn
	 *    4 - Ruchy bez znaczenia (Dealer, rozdanie kart)
	 *    
	 * inputDataD1:
	 * [0] - True/False
	 * [1] - Pozycja gracza / Komunikat błędu
	 * 
	 * inputDataD2: (Gdy Koniec Tury)
	 * [0] - Stan konta gracza
	 * [1] - Całkowita Póla Stołu
	 * 
	 * -- Dot. msg. o ruchu [DL - długość D2]
	 * [DL - 2] - Kod Wiadomości
	 * [DL - 1] - Argument wiadomości
	 * 
	 * </pre>
	 * 
	 * 
	 * @param cfgData
	 * @param pID
	 * @param inputDataD1
	 * @param inputDataD2
	 */
	private void broadCastAboutPlayerMove(final int cfgData[], final String pID, final Object[] inputDataD1, final Object[][] inputDataD2)
	{
		broadcastMessageToAll(new Object[] {0 , pID}, jsonSchema(
				0x03, 
				new int[] {
					0x02,
					cfgData[0],
					cfgData[1]
							
				}, 
				inputDataD1,
				inputDataD2));
	}
	
	
	
	/**
	 * 
	 * Przesyła wiadomości / dane od Serwera do wszystkich użytkoników lub pojedyńczego.
	 * 
	 * <pre>
	 * cfgData:
	 * 	[0] - Tryb działania
	 * 		0 - Wszyscy
	 * 		1 - Jeden osobnik
	 *  [1] - Obiekt gracza //Dot. gdy tryb jeden osobnik
	 *  [2] - GamaEvenID
	 *  	0 - Zdarzenia dot. Konkretnego etapu gry
	 *      1 - Zdarzenia dot. Gracza lub jego ruchów
	 * 
	 *  inputDataD1:
	 *  [0] - True / False
	 *  
	 *  (GameEvent: 0)
	 *  [1] Kod błędu (gdy false) | Etap gry | (Informacja dla gracz o pewnych zdarzeniach)
	 *    (Etap gry:)
     *    1 - Rozpoczęcie gry
     *    2 - Wybór Dealera
     *    3 - Rozdanie kart poczatkowe
	 *    4 - Licytacja
	 *    5 - Koniec Gry (Wyniki)
	 *    
	 *    [2] - DealerNickName
	 *    [3] - Nr. Rozdania
	 *    
	 *    [DL - 2] - ID komunikatu
	 *    [DL - 1] - Argument
	 *    
	 *  (GameEvent: 1)
	 *  [1] Kod błędu (gdy false) | Etap gry | (Informacja dla gracz o pewnych zdarzeniach)
	 *    (Informacja dla gracz o pewnych zdarzeniach: )
	 *    0 - Został wybrany na Dealera
	 *    1 - Trwa Wymiana Kart
	 *    2 - Teraz jego tura na ruch
	 *    3 - Przekroczył czas na ruch (Serwer go "foldnął")

	 * 
	 * </pre>
	 * 
	 * 
	 * @param cfgData
	 * @param inputDataD1
	 * @param inputDataD2
	 */
	private void broadcastAboutGameEnviromentEvent(final Object cfgData[], final Object[] inputDataD1, final Object[][] inputDataD2)
	{
		//Def.
		Core_JsonDataSchema schema;
		
		//Init.
		schema = jsonSchema(
				0x03, 
				new int[] {
					0x03,
					(Integer)cfgData[2]
							
				}, 
				inputDataD1,
				inputDataD2);

		
		
		if((Integer) cfgData[0] == 0)
		{
			broadcastMessageToAll(new Object[] {1 , null}, schema);
		}
		else
		{
			//Def.
			Player tmpPlayer;
			
			//Init.
			tmpPlayer = (Player) cfgData[1];
			
			
			
			tmpPlayer.getMyThread().sendData(schema);
		}
	}
		
	//=====================================================================================
	
	
	/**
	 * Funkcja zatwierdzena stan gotowości i sprawdza czy gracz nie był wczesniej gotowy
	 * 
	 * @param idPlayer
	 * @return
	 */
	public Object[] submitReadyStatus(Player objP)
	{
		//Def.
		Object[] result;
		
		//Init
		result = new Object[] {
			false,
			null
		};
		
		if(!isReady( objP.getPlayerId() ))
		{
			
			//Ustawienie statusu
			tabPlayers.get( objP.getPlayerId() )[2] = true;
			
			//Zwiększenie ilości gotowych graczy
			gameData[2] += 1;
			
			
			//Global Event
			broadcastTextEvent(objP.getPlayerId(), new Object[] {
				"| " + objP.getNickName() +  " | - ", 0x03D0
			});
			
			result[0] = true;
			
			//Sprawdzenie gotowości do gry
			gameInitCheck();
		}
		else
		{
			result[1] = 0x03D8;
		}
		
		
		return result;
	}
	
	
	
	/**
	 * 
	 * Jeżeli wszyscy gracze są gotowi i ich liczba wynosi conajmniej 2 rozpocznie się gra
	 * 
	 */
	public void gameInitCheck()
	{
		
		if(gameData[2] == settingsTable[1] && settingsTable[1] > 1)
		{
			//Wygenerowanie listy graczy
			this.gameTh.start();
		}
	}
	

	
	
	//------------------ [movies] - #START ------------------
	
	
	//------------------ [moves] - #END ------------------

	
	
	
	
	//------------------ [setters] - #START ------------------

	
	/**
	 * Ustawia Identyfikator stołu
	 * 
	 * @return
	 */
	public void setTableId(String nTableID)
	{
		this.tableID = nTableID;

		//Aktualizacja
		updateParcipantsTabID();

	}
	
	

	
	//------------------ [setters] - #END ------------------
	
	
	
	//------------------ [getters] - #START ------------------
	

	
	/**
	 * Zwaraca informacje o statusie stołu
	 * @return
	 */
	public int getStatus()
	{
		return this.status;
	}
	
	/**
	 * Funkcja zwraca nazwę stołu
	 * 
	 * @return
	 */
	public String getName()
	{
		return this.textData[0];
	}
	
	
	/**
	 * Funkcja zwraca ilość graczy i obserwatorów
	 * 
	 * @return
	 */
	public String getCountOfPlayersAndObservers()
	{
		return Integer.toString(settingsTable[1]) + " / " + Integer.toString(settingsTable[2]) + "  |  " +
			Integer.toString(settingsTable[3]) + " / " + Integer.toString(settingsTable[4]);
	}
	
	
	/**
	 * Funkcja zwraca minimalną ilość pieniędzy wymaganą, aby wejśc do stołu
	 * 
	 * @return
	 */
	public int getMinCash()
	{
		return settingsTable[ 5 ];
	}
	
	
	
	/**
	 * Funkcja zwraca  czas ruchu gracza w ms
	 * 
	 * @return
	 */
	public int getPlayerMovetime()
	{
		return settingsTable[ 8 ] * 1000;
	}
	
	/**
	 * Zwraca Identyfiaktor stołu
	 * 
	 * @return
	 */
	public String getTableId()
	{
		return this.tableID;
	}
	
	
	/**
	 * Zwraca informacje czy gracz jest gotowy
	 * 
	 * @param playerID
	 * @return
	 */
	public boolean isReady(String playerID)
	{		
		return (boolean) tabPlayers.get(playerID)[2];
	}
	
	
	
	//------------------ [getters] - #END ------------------
	
	
	
	
	
	//------------------ [ADVgetters] - #START ------------------
	/**
	 * 
	 * Pobiera Informacje o stole i o graczach (Po za graczem którego id jest w parametrze!!!)
	 * 
	 * @param pID
	 * @return
	 */
	public Object[][] getTableData(String pID)
	{
		//Def.
		int posAbs;
		
		if(!this.tabPlayers.containsKey(pID))
		{
			posAbs = -1;
		}
		else
		{
			posAbs = (Integer) this.tabPlayers.get(pID)[4];
		}
		
		
		Object[][] data = new Object[2][];
		
		//Dane stołu
		data[0] = new Object[] {
			0, //Póla
			status == 2 ? true : false,//Status gry Trwa, czy nie
			adminID, //AdminName
			getDealerName(), //DealerNamer
			this.gameData[5], //Nr. Rozdania / Licytacji / Rundy
			posAbs //Absolutna pozycja gracza
		};
		
		
		//Dane o graczach [ID_POZ, Login, Cash, LastMove, LM_Args]
		/** posAbs jeżeli jest rózne od -1 świadczy o tym, że mamy do czynienia z graczem*/
		if(posAbs != -1)
		{
			data[1] = new Object[ (settingsTable[1] - 1) * 6 ];
		}
		else
		{
			data[1] = new Object[ (settingsTable[1]) * 6 ];
		}
		
		
		//Def.
		Object[] tmpD; //Przechowuje wyniki
		Player tmpPl; 
		final Serwer srv; //Uchwyt do serwera
		int k; //Pozycja gracza na stole
		
		//init
		srv = Controler.getcSerwer();
		k = 0;
		
		for(final String objID : this.tabPlayers.keySet())
		{
			//Pobiera dane po za graczem
			if(objID != null && !objID.equals(pID))
			{
				
				
				tmpD = srv.getPlayer(objID);
								
				if((boolean) tmpD[0] == true)
				{
					tmpPl = (Player) tmpD[1];
					
					data[1][k] = (Integer) this.tabPlayers.get(objID)[4]; //Pozycja gracza
					data[1][++k] = tmpPl.getNickName();
					data[1][++k] = tmpPl.getFunds();
					data[1][++k] = (Integer) this.tabPlayers.get(objID)[1]; //PlayerBid
					
					if((boolean) data[0][1])
					{
						tmpD = getMoveHistory(objID);
						
						
						data[1][++k] =  tmpD[0]; //MoveID
						data[1][++k] =  tmpD[1]; //Arguments
					}
					else
					{
						data[1][++k] = -1;
						data[1][++k] = 0;
					}
					
					//Zwiększenia liczników
					++k;
				}
			}
		}
		
		
		
		
		
		return data;
	}
	
	
	
	/**
	 * Pobiera informacje o graczu  + o Stole
	 * 
	 * @param pID
	 * @return
	 */
	public Object[][] getPlayerData(String pID)
	{
		//Def & init.
		Object[][] data;
		Object[] pData;
		
		
		//Init
		data = new Object[2][];
		pData = this.tabPlayers.get(pID);
		
		
		if(pData != null)
		{
			//Dane stołu
			data[0] = new Object[] {
				0, //Póla
				status == 2 ? true : false,//Status gry Trwa, czy nie
				adminID, //AdminName
				getDealerName(), //DealerNamer
				this.gameData[5], //Nr. Rozdania / Licytacji / Rundy
				(Integer) pData[4] //Absolutna pozycja gracza
			};
			
			
			//Dane o graczach [ID_POZ, Login, Cash, LastMove, LM_ARGS]
			data[1] = new Object[ 6 ];
			
			
			//Def.
			Object[] tmpD; //Przechowuje wyniki
			Player tmpPl; 
			final Serwer srv; //Uchwyt do serwera
			int k; //Pozycja gracza na stole
			
			//init
			srv = Controler.getcSerwer();
			k = 0;
			
			
	
			tmpD = srv.getPlayer(pID);
					
			if((boolean) tmpD[0] == true)
			{
				tmpPl = (Player) tmpD[1];
	
						
				data[1][k] = pData[4]; //Pozycja gracza
				data[1][++k] = tmpPl.getNickName();
				data[1][++k] = tmpPl.getFunds();
				data[1][++k] = pData[1]; //PlayerBid
						
				if((boolean) data[0][1])
				{
					tmpD = getMoveHistory(pID);
							
							
					data[1][++k] =  tmpD[0]; //MoveID
					data[1][++k] =  tmpD[1]; //Arguments
				}
				else
				{
					data[1][++k] = -1;
					data[1][++k] = 0;
				}
						
				++k;
			}
	
		}
		
		
		
		return data;
	}
	//------------------ [ADVgetters] - #END ------------------

	
	
	
}
